package com.sinodata.bsm.cicp.collector.oracle;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.CommandReader;
import com.sinodata.bsm.common.vo.ResPropertyValue;

public class TNSPingCollector extends Collector {
    private static final Logger logger = Logger.getLogger(TNSPingCollector.class);
    private static final int times = 5;

    private static final String cmd = "uname";
    private static final String OS_Linux = "Linux";
    private static final String OS_AIX = "AIX";
    private static final String OS_Solaris = "SunOS";
    private static final String OS_HP = "HP-UX";
    private static final String OS_Tru64 = "OSF1";

    private static final String cmd_Windows = "ping -n " + times + " ";
    private static final String cmd_Linux = "ping -c " + times + " ";
    private static final String cmd_AIX = "ping -c " + times + " ";
    private static final String cmd_Solaris = "ping -s ";
    private static final String cmd_HP = "ping ";
    private static final String cmd_Tru64 = "/usr/sbin/ping -c " + times + " ";

    private static final String rut_windows = "\\s+Packets:\\s+Sent\\s+=\\s+(\\d+),\\s+Received\\s+=\\s+(\\d+),\\s+Lost\\s+=\\s+\\d+\\s+\\((\\d+)%.*";
    private static final String rut_linux = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+received.*,\\s+(\\d+)%.*";
    private static final String rut_aix = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
    private static final String rut_solaris = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";
    private static final String rut_hp = "(\\d+)\\s+packets\\s+transmitted,\\s+(\\d+)\\s+packets\\s+received,\\s+(\\d+)%.*";

    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        List<ResPropertyValue> values = new ArrayList<ResPropertyValue>();
        String[] propMetas = getPropMeta();
        ResPropertyValue propertyValueX = new ResPropertyValue();
        ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
        String tnspingIp = this.getParamMap().get("TNSPING_IP");//tnsping对象主机的IP
        String pingTest = testPing(ip, tnspingIp);
        if (pingTest.equals("not connect")) {
            propValues[0] = ResPropertyValue.createPropValue(pingTest, propMetas[0]);
            propValues[1] = ResPropertyValue.createPropValue("N/A", propMetas[1]);
            propertyValueX.setValues(propValues);
            values.add(propertyValueX);
            return values;
        }
        int lost = Integer.parseInt(pingTest);
        BufferedReader br = null;
        String tnsCmd = "tnsping " + tnspingIp;
        try {
            Pattern noLisStr = Pattern.compile("TNS-12541:\\s+TNS:no\\s+listener");
            Pattern okStr = Pattern.compile("OK\\s+\\((\\d+)\\s+.*\\)");
            if (lost <= 40) {
                br = CommandReader.getReader(ip, tnsCmd, 0, 0);
                String line = br.readLine();
                while (line != null) {
                    Matcher matcher = noLisStr.matcher(line);
                    if (matcher.find()) {
                        propValues[0] = ResPropertyValue.createPropValue("no listener", propMetas[0]);
                        propValues[1] = ResPropertyValue.createPropValue("N/A", propMetas[1]);
                        propertyValueX.setValues(propValues);
                        values.add(propertyValueX);
                        return values;
                    }
                    matcher = okStr.matcher(line);
                    if (matcher.find()) {
                        // MatchResult match = matcher.getMatch();
                        propValues[0] = ResPropertyValue.createPropValue("OK", propMetas[0]);
                        propValues[1] = ResPropertyValue.createPropValue(matcher.group(1).trim(), propMetas[1]);
                        propertyValueX.setValues(propValues);
                        values.add(propertyValueX);
                        return values;
                    }
                    line = br.readLine();
                }
            } else {
                propValues[0] = ResPropertyValue.createPropValue("not connect", propMetas[0]);
                propValues[1] = ResPropertyValue.createPropValue("N/A", propMetas[1]);
                propertyValueX.setValues(propValues);
                values.add(propertyValueX);
                return values;
            }
        } catch (IOException ex) {
            propValues[0] = ResPropertyValue.createPropValue("not connect", propMetas[0]);
            propValues[1] = ResPropertyValue.createPropValue("N/A", propMetas[1]);
            propertyValueX.setValues(propValues);
            values.add(propertyValueX);
            return values;

        } finally {
            try {
                if (br != null)
                    br.close();
            } catch (IOException e) {
                logger.error("failed to close BufferedReader", e);
            }
        }
        return null;
    }

    private String getCommand(String ip, String targetIp) {
        BufferedReader br = null;
        try {
            br = CommandReader.getReader(ip, cmd, 0, 0);
            String osName = br.readLine();
            String cmd = cmd_Windows + " " + targetIp;
            // 返回适合该cmdserver所在操作系统的ping命令
            if (osName.equals(OS_Linux)) {
                cmd = cmd_Linux + targetIp;
            } else if (osName.equals(OS_AIX)) {
                cmd = cmd_AIX + targetIp;
            } else if (osName.equals(OS_Solaris)) {
                cmd = cmd_Solaris + targetIp + " 56 " + times + "";
            } else if (osName.equals(OS_HP)) {
                cmd = cmd_HP + targetIp + " -n " + times + "";
            } else if (osName.equals(OS_Tru64)) {
                cmd = cmd_Tru64 + targetIp;
            }
            return cmd;
        } catch (IOException ex) {
            return cmd_Windows + " " + targetIp;
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                logger.error("failed to close BufferedReader", e);
            }
        }
    }

    private String testPing(String pIp, String cIp) throws CollectorException {
        String pingCmd = getCommand(pIp, cIp);
        BufferedReader br = null;
        try {
            br = CommandReader.getReader(pIp, pingCmd, 0, 0);
            String line = br.readLine();
            List l = getPattern(pIp);
            if (l == null || l.size() < 2) {
                return "not connect";
            }
            if (l.get(0) instanceof Pattern) {
                Pattern CURRENT_PATTERN1 = (Pattern) l.get(0);
                while (line != null) {
                    Matcher matcher = CURRENT_PATTERN1.matcher(line);
                    if (matcher.find()) {
                        return matcher.group(3).trim();
                    }
                    line = br.readLine();
                }
            }
        } catch (IOException ex) {
            logger.error("failed to test ping", ex);
        } finally {
            try {
                br.close();
            } catch (IOException e) {
                logger.error("failed to close BufferedReader", e);
            }
        }
        return "not connect";
    }

    private List getPattern(String ip) throws CollectorException {
        Pattern compiler = null;
        ArrayList l = new ArrayList();
        BufferedReader br = null;
        String rut_type = rut_windows;
        String os = "windows";
        try {
            br = CommandReader.getReader(ip, cmd, 0, 0);
            String osName = br.readLine();
            // 返回适合该cmdserver所在操作系统的ping命令
            if (osName.equals(OS_Linux)) {
                rut_type = rut_linux;
                os = "linux";
            } else if (osName.equals(OS_AIX)) {
                rut_type = rut_aix;
                os = "aix";
            } else if (osName.equals(OS_Solaris)) {
                rut_type = rut_solaris;
                os = "solaris";
            } else if (osName.equals(OS_HP)) {
                rut_type = rut_hp;
                os = "hp";
            }
            l.add(compiler.compile(rut_type));
            l.add(os);
            return l;
        } catch (IOException ex) {
            logger.error("failed to get pattern", ex);
            throw new CollectorException(ex);
        } finally {
            IOUtils.closeQuietly(br);
        }
    }

    @Override
    public String[] getParamMeta() {
        return new String[] { "TNSPING_IP" };
    }

    @Override
    public String[] getPropMeta() {
        return new String[] { "PING_STATUS", "TNS_TIME" };
    }

}
